package de.urw.core;

import java.lang.reflect.Field;
import java.util.ArrayList;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.content.res.AssetManager;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Light;
import com.threed.jpct.Loader;
import com.threed.jpct.Logger;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Polyline;
import com.threed.jpct.Primitives;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.example.R;
import com.threed.jpct.util.BitmapHelper;
import com.threed.jpct.util.MemoryHelper;

import de.urw.app.URWKit;
import de.urw.app.URWKitObject;

/**
 * A simple demo. This shows more how to use jPCT-AE than it shows how to write
 * a proper application for Android. It includes basic activity management to
 * handle pause and resume...
 * 
 * @author EgonOlsen
 * 
 */

//...............

public class renderActivity extends Activity {

	// Used to handle pause and resume...
	private static renderActivity master = null;

	private GLSurfaceView mGLView;
	private MyRenderer renderer = null;
	private FrameBuffer fb = null;
	private World world = null;
	private RGBColor back = new RGBColor(50, 50, 100);

	private float touchTurn = 0;
	private float touchTurnUp = 0;

	private float xpos = -1;
	private float ypos = -1;

	//private Object3D cube = null;
	private int fps = 0;

	private Light sun = null;
	
	private URWKit parser;
	
	public static AssetManager assMan;
	
	public ArrayList<URWKitObject> objects;
	public ArrayList<URWnode> URWbranches = new ArrayList<URWnode>();
	public ArrayList<Object3D> obj3D = new ArrayList<Object3D>();
	public ArrayList<URWedge> URWedges = new ArrayList<URWedge>();
	public ArrayList<URWnode> URWshops = new ArrayList<URWnode>();
	

	protected void onCreate(Bundle savedInstanceState) {

		Logger.log("onCreate");

		if (master != null) {
			copy(master);
		}

		super.onCreate(savedInstanceState);
		mGLView = new GLSurfaceView(getApplication());

		mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
			public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
				// Ensure that we get a 16bit framebuffer. Otherwise, we'll fall
				// back to Pixelflinger on some device (read: Samsung I7500)
				int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
				EGLConfig[] configs = new EGLConfig[1];
				int[] result = new int[1];
				egl.eglChooseConfig(display, attributes, configs, 1, result);
				return configs[0];
			}
		});
		
		assMan = getAssets();
		
		//parser = new URWKit("../src/modules");
		
		//D:/dev/android/eclipse/workspace/HelloWorld-AE/src/modules
		parser = new URWKit("file:///android_asset/modules/"); //absoluter pfad, so narrisch bin ich
		Log.d("test", "initialized urwkit");
		parser.loadModules();
		Log.d("test", "loaded modules");
		parser.readXML(getResources().openRawResource(R.raw.data));
		Log.d("test", "read xml");
		
		objects = parser.xmlp.xmlol.objects;

		
		
		renderer = new MyRenderer();
		mGLView.setRenderer(renderer);
		setContentView(mGLView);
		
	}

	@Override
	protected void onPause() {
		super.onPause();
		mGLView.onPause();
	}

	@Override
	protected void onResume() {
		super.onResume();
		mGLView.onResume();
	}

	@Override
	protected void onStop() {
		super.onStop();
	}

	private void copy(Object src) {
		try {
			Logger.log("Copying data from master Activity!");
			Field[] fs = src.getClass().getDeclaredFields();
			for (Field f : fs) {
				f.setAccessible(true);
				f.set(this, f.get(src));
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public boolean onTouchEvent(MotionEvent me) {

		if (me.getAction() == MotionEvent.ACTION_DOWN) {
			xpos = me.getX();
			ypos = me.getY();
			return true;
		}

		if (me.getAction() == MotionEvent.ACTION_UP) {
			xpos = -1;
			ypos = -1;
			touchTurn = 0;
			touchTurnUp = 0;
			return true;
		}

		if (me.getAction() == MotionEvent.ACTION_MOVE) {
			float xd = me.getX() - xpos;
			float yd = me.getY() - ypos;

			xpos = me.getX();
			ypos = me.getY();

			touchTurn = xd / -100f;
			touchTurnUp = yd / -100f;
			return true;
		}

		try {
			Thread.sleep(15);
		} catch (Exception e) {
			// No need for this...
		}

		return super.onTouchEvent(me);
	}

	protected boolean isFullscreenOpaque() {
		return true;
	}

	class MyRenderer implements GLSurfaceView.Renderer {

		private long time = System.currentTimeMillis();
		private Camera cam;
		
		public MyRenderer() {
			
		}

		public void onSurfaceChanged(GL10 gl, int w, int h) {
			if (fb != null) {
				fb.dispose();
			}
			fb = new FrameBuffer(gl, w, h);

			if (master == null) {

				world = new World();
				world.setAmbientLight(20, 20, 20);

				sun = new Light(world);
				sun.setIntensity(250, 250, 250);

				// Create a texture out of the icon...:-)
				Texture textureWhite = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.white)), 64, 64));
				TextureManager.getInstance().addTexture("white", textureWhite);
				Texture textureBluegrey = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.bluegrey)), 64, 64));
				TextureManager.getInstance().addTexture("bluegrey", textureBluegrey);
				
				//createObject(R.raw.treppe, 0, 0);
				
				float scale = 3.0f;
				float shiftX = -700;
				float shiftY = -1000;
				int k = 1;
				int edgeCount = 0;
				
				ArrayList<SimpleVector> edges = new ArrayList<SimpleVector>();
				
				
				
				for(URWKitObject obj : objects)
				{
					if(obj.get("storey") != null)
					{
						Log.d("test", "storey");
						if(obj.get("storey").equals("1")) break;
					}
					
					if(	obj.get("id") != null && 
						obj.get("source") != null &&
						obj.get("sink") != null)
					{
						URWedges.add(new URWedge(	Integer.parseInt((String)obj.get("id")),
													Integer.parseInt((String)obj.get("source")),
													Integer.parseInt((String)obj.get("sink"))));
						
						//Log.d("test", "add urwedge");
					}
					
					//((String)obj.get("type")).equals("Shop")
					if(obj.get("id") != null && obj.get("x") != null && obj.get("y") != null && obj.get("type") != null)
					{
						//Log.d("test", "add...");
						if(obj.get("type").equals("Shop"))
						{
							
							URWshops.add(new URWnode(	Integer.parseInt((String)obj.get("id")),
														Integer.parseInt((String)obj.get("x")) * scale + shiftX,
														Integer.parseInt((String)obj.get("y")) * scale + shiftY));
							
							//Log.d("test", "add shop...");
							createObject(R.raw.treppe, Float.parseFloat((String)obj.get("x")) * scale + shiftX, Float.parseFloat((String)obj.get("y")) * scale + shiftY, true);
							//Log.d("test", "shop done");
						}
						else if(obj.get("type").equals("branch"))
						{
							//Log.d("test", "add branch");
							
							URWbranches.add(new URWnode(	Integer.parseInt((String)obj.get("id")),
															(int)(Integer.parseInt((String)obj.get("x")) * scale + shiftX),
															(int)(Integer.parseInt((String)obj.get("y")) * scale + shiftY)));
							/*URWbranches.add(new URWnode(	0,
															0,
															0, "a", "a"));*/
							
							Log.d("test", "added branch");
							
							//Log.d("test", "add branch...");
							//edges.add(new SimpleVector(Float.parseFloat((String)obj.get("x")) * scale + shiftX, 3.0f, Float.parseFloat((String)obj.get("y")) * scale + shiftY));
							edgeCount++;
							//Log.d("test", "branch done");
						}
						//Log.d("test", t + " " + x + " " + y);
						
						
						//createObject(R.raw.treppe, k * 5, 0);
						
						//Log.d("test", (String)obj.get("x"));
						
						//k += 1;
						//if(k > 5) break;
					}
				}
				
				Log.d("test", "blub...");
				
				for(URWedge e : URWedges)
				{
					if(e.init(URWbranches)) world.addPolyline(createLine(e));
				}
				
				URWwall urwwall = new URWwall();
				ArrayList<int[]> URWwalls = new ArrayList<int[]>();
				URWwalls = urwwall.createWalls(URWshops, URWedges);
				
				Log.d("walls","TEST " + URWwalls.get(0)[0] + ", " + URWwalls.get(0)[1] + ", " + URWwalls.get(0)[2] + ", " + URWwalls.get(0)[3]);
				
				for(int[] e : URWwalls) {
					world.addPolyline(createWall(e[0], e[1], e[2], e[3]));
					//Log.d("walls","" + e[0] + ", " + e[1] + ", " + e[2] + ", " + e[3]);
				}
				
				// +++ Polyline +++
				/*Log.d("test", "creating polyline...");
				
				SimpleVector[] testEdge = new SimpleVector[edgeCount];
				
				int i = 0;
				for(SimpleVector v : edges)
				{
					if(i >= edgeCount) break;
					Log.d("test", "line: " + v.x + " " + v.y + " " + v.z);
					testEdge[i] = v;
					i++;
				}
				
				//testEdge[0] = new SimpleVector(0, 5, 0);
				//testEdge[1] = new SimpleVector(10, 5, 10);
				
				Polyline temp = new Polyline(testEdge, new RGBColor(100, 150, 200));
				//Polyline temp = new Polyline((SimpleVector[]) edges.toArray(), new RGBColor(100, 150, 200));
				temp.setWidth(20);
				
				Log.d("test", "adding polyline...");
				//RGBColor temp = new RGBColor(100, 150, 200);
				world.addPolyline(temp);
				
				*/
				
				Log.d("test", "yay");
				
				
				
				//cube = Primitives.getCube(10);
				Object3D plane = Primitives.getPlane(1, 2000.0f);// = loadModel(model, 10);
		
				plane.calcTextureWrap();
				plane.setTexture("bluegrey");
				plane.strip();
				plane.build();
				plane.translate(0, 13.0f, 0);
				plane.rotateX((float)(Math.PI * 0.5f));
				
				
				world.addObject(plane);
				
				

				//cam = world.getCamera();
				
				/*
				//original
				if(cam == null) cam = world.getCamera();
				cam.moveCamera(Camera.CAMERA_MOVEUP, 20);
				cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
				cam.lookAt(plane.getTransformedCenter());*/
				
				//test
				if(cam == null) cam = world.getCamera();
				cam.moveCamera(Camera.CAMERA_MOVEUP, 120);
				cam.moveCamera(Camera.CAMERA_MOVEOUT, 80);
				cam.lookAt(plane.getTransformedCenter());

				SimpleVector sv = new SimpleVector();
				sv.set(plane.getTransformedCenter());
				sv.y -= 100;
				sv.z -= 100;
				sun.setPosition(sv);
				MemoryHelper.compact();

				if (master == null) {
					Logger.log("Saving master Activity!");
					master = renderActivity.this;
				}
			}
		}

		
		
		/*private Object3D createPlaneLine(URWedge e)
		{
			Log.d("test", "getting vectors...");
			
			SimpleVector testEdge[] = new SimpleVector[2];
			
			testEdge[0] = e.source.vector;
			testEdge[1] = e.sink.vector;
			
			Log.d("test", "creating polyline...");
			
			
			Object3D plane = Primitives.getPlane(1, testEdge[0].distance(testEdge[1]));

			plane.rotateY(testEdge[0].calcAngleFast(testEdge[1]));
			
			plane.
			
			plane.calcTextureWrap();
			plane.setTexture("red");
			
			
			plane.strip();
			plane.build();
			plane.translate(0, 13.0f, 0);
			plane.rotateX((float)(Math.PI * 0.5f));
			
			
			
			
			Polyline temp = new Polyline(testEdge, );
			//Polyline temp = new Polyline((SimpleVector[]) edges.toArray(), new RGBColor(100, 150, 200));
			temp.setWidth(20);
			
			Log.d("test", "done!");
			
			//RGBColor temp = new RGBColor(100, 150, 200);
			//world.addPolyline(temp);
			
			return plane;
		}*/
		
		private Polyline createLine(URWedge e)
		{
			Log.d("test", "getting vectors...");
			
			SimpleVector testEdge[] = new SimpleVector[2];
			
			testEdge[0] = e.source.vector;
			testEdge[1] = e.sink.vector;
			
			
			Log.d("test", "creating polyline...");
			
			Polyline temp = new Polyline(testEdge, new RGBColor(100, 150, 200));
			//Polyline temp = new Polyline((SimpleVector[]) edges.toArray(), new RGBColor(100, 150, 200));
			temp.setWidth(20);
			
			Log.d("test", "done!");
			
			//RGBColor temp = new RGBColor(100, 150, 200);
			//world.addPolyline(temp);
			
			return temp;
		}
		
		private Polyline createWall(int x1, int y1, int x2, int y2)
		{
			Log.d("test", "getting vectors...");
			int height = 10;
			SimpleVector testEdge[] = new SimpleVector[2];
			
			testEdge[0] = new SimpleVector(x1, height, y1);
			testEdge[1] = new SimpleVector(x2, height, y2);
			
			
			Log.d("test", "creating polyline...");
			
			Polyline temp = new Polyline(testEdge, new RGBColor(250, 0, 0));
			//Polyline temp = new Polyline((SimpleVector[]) edges.toArray(), new RGBColor(100, 150, 200));
			temp.setWidth(20);
			
			Log.d("test", "done!");
			
			//RGBColor temp = new RGBColor(100, 150, 200);
			//world.addPolyline(temp);
			
			return temp;
		}
		
		private Object3D createObject(int model, float x, float z)
		{
			SimpleVector v = new SimpleVector();
			v.x = x;
			v.z = z;
			v.y = 0;
			//cube = Primitives.getCube(10);
			Object3D cube = loadModel(model, 10);
			if(cube == null)
			{
				cube = Primitives.getCube(10);
			}
			cube.calcTextureWrapSpherical();
			cube.setTexture("white");
			cube.strip();
			cube.build();
			cube.rotateX((float)(Math.PI / 2.0f));
			
			cube.translate(v);
		
			world.addObject(cube);
			
			return cube;
		}
		
		private Object3D createObject(int model, float x, float z, boolean placeholder)
		{
			SimpleVector v = new SimpleVector();
			v.x = x;
			v.z = z;
			v.y = 0;
			//cube = Primitives.getCube(10);
			Object3D cube = loadModel(model, 10);
			if(cube == null || placeholder)
			{
				cube = Primitives.getCube(8);
			}
			cube.calcTextureWrapSpherical();
			cube.setTexture("white");
			cube.strip();
			cube.build();
			//cube.rotateX((float)(Math.PI / 2.0f));
			
			cube.translate(v);
		
			world.addObject(cube);
			
			return cube;
		}
		
		public void onSurfaceCreated(GL10 gl, EGLConfig config) {
			//cam = world.getCamera();
		}

		public void onDrawFrame(GL10 gl) {
			if(cam == null) cam = world.getCamera();
			if (touchTurn != 0) {
				//cube.rotateY(touchTurn);
				//cam.rotateCameraAxis(SimpleVector.create(0, 1, 0), touchTurn);
				cam.moveCamera(SimpleVector.create(1, 0, 0), touchTurn * 100);//setPosition((float)(cam.get + (10.0f * touchTurn)), cam.getYAxis(), cam.getZAxis());
				touchTurn = 0;
			}

			if (touchTurnUp != 0) {
				//cube.rotateX(touchTurnUp);
				//cam.rotateX(touchTurn);
				cam.moveCamera(SimpleVector.create(0, 0, 1), touchTurnUp * -100);
				touchTurnUp = 0;
			}

			fb.clear(back);
			world.renderScene(fb);
			world.draw(fb);
			fb.display();

			if (System.currentTimeMillis() - time >= 1000) {
				Logger.log(fps + "fps");
				fps = 0;
				time = System.currentTimeMillis();
			}
			fps++;
		}
		
		private Object3D loadModel(int file, float scale) {
			try {
				Object3D[] model = Loader.loadOBJ(getResources().openRawResource(file), null, scale);

				Object3D o3d = new Object3D(0);
		        Object3D temp = null;
		        for (int i = 0; i < model.length; i++) {
		            temp = model[i];
		            temp.setCenter(SimpleVector.ORIGIN);
		            temp.rotateX((float)( -.5*Math.PI));
		            temp.rotateMesh();
		            temp.setRotationMatrix(new Matrix());
		            o3d = Object3D.mergeObjects(o3d, temp);
		            o3d.build();
		        }
		        return o3d;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
	        
	        
	    }
	}
}
